<?php
// TODO: some more security staff?
// e.g.: htmlspecialchars

// Check whether magic quotes is off
if(!get_magic_quotes_gpc())
{
	// Add the slashes manually
	arrayAddslashes($GET);
	arrayAddslashes($POST);
	arrayAddslashes($COOKIE);
}

// Register an own error handler
set_error_handler('errorHandler');

/**
 * Class autoloader.
 *
 * This function is called every time a not yet loaded
 * class is used. The method automatically includes this
 * file so it can be used after.
 *
 * @param string $className
 */
function __autoload($classname)
{
	// Get the path for the class name
	$path = classnameToPath($classname);

	// Include path
	include_once($path);
}

/**
 * Recursively escape all strings of an array
 *
 * @param array &$var
 */
function arrayAddslashes(&$var)
{
	// Check whether the given variable is a string
	if(is_string($var))
	{
		// Escape the string
		$var = addslashes($var);
	}
	// Check whether the given variable is an array
	elseif(is_array($var))
	{
		// Iterate over all elements
		foreach($var AS $key => $value)
		{
			// Do the same again for the value
			arrayAddslashes($var[$key]);
		}
	}
}

/**
 * Converts a classname into the path.
 * E.g. Core_App -> Core/App.
 *
 * This method appends also the php mimetype by default.
 * E.g. Core_App -> Core/App.php
 *
 * @param string  $namespace
 * @param boolean $appendPhp
 * @return string
 */
function classnameToPath($namespace, $appendPhp = true)
{
	// Replace the underscored with the path separator
	$path = str_replace('_', DS, $namespace);

	// Check whether we want to add the php mime type
	if($appendPhp)
	{
		// Add .php
		return $path.'.php';
	}

	// Return the result
	return $path;
}

/**
 * Converts a namespace into a classname.
 * E.g. core/app -> Core_App.
 *
 * If $slashReplace is given, the method will insert the given replacor
 * at the location of the slash.
 * E.g. core/app -> Core_Model_App (when 'model' is given as $slashReplace).
 *
 * @param string      $namespace
 * @param string|null $slashReplace
 * @return string
 */
function namespaceToClassname($namespace, $slashReplace = null)
{
	trigger_error('this is deprecated');
	// Check whether the slashreplace is not null
	if($slashReplace !== null)
	{
		// Replace the slash with the given replaceor
		$namespace = str_replace('/', '_'.$slashReplace.'_', $namespace);
	}
	// No slashreplace was given
	else
	{
		// Replace the slash with a underscore
		$namespace = str_replace('/', '_', $namespace);
	}

	// Make the words uppercase
	$namespace = str_replace('_', ' ', $namespace);
	$namespace = ucwords($namespace);
	$namespace = str_replace(' ', '_', $namespace);

	// Return the classname
	return $namespace;
}

/**
 * Removes the constant PATH_BASE from the given path string.
 * This is for paths to be more comfortable to read.
 *
 * @param string $path
 * @return string
 */
function removePathBaseFromPath($path)
{
	// Return the path without the PATH_BASE
	return str_replace(PATH_DIR, '', $path);
}

/**
 * Provides an error handler for basic errors that can be handled by a custom function.
 * This error handler collects data like the stack and the error label and calls the function
 * to display the stack.
 *
 * @param int    $errorNumber
 * @param string $errorString
 * @param string $errorFile
 * @param int    $errorLine
 * @param string $errorContext
 */
function errorHandler($errorNumber, $errorString, $errorFile, $errorLine, $errorContext)
{
	// Check whether the error reporting settings fit the error
	if(!(error_reporting() & $errorNumber))
	{
		// End function
		return;
	}

	// Create label buffer
	$errorLabel;

	// Iterate over all defined constants to get the current error name
	foreach(get_defined_constants() as $constantLabel => $constantNumber)
	{
		// Check whether the constant label begins with E_ and has as value the errorNumber
		if(substr($constantLabel, 0, 2) == 'E_' && $constantNumber === $errorNumber)
		{
			// Set the error label as the current contant label
			$errorLabel = $constantLabel;
		}
	}

	// Get the backtrace array
	$stacktrace = debug_backtrace();

	// Delete entry for the error handler
	unset($stacktrace[0]);

	// Display this error
	displayTrace($errorLabel, $errorString, $errorFile, $errorLine, $stacktrace);
}


/**
 * Provides an exception handler that simply passes all required data to the function
 * that displays a stacktrace nicely.
 *
 * @param Exception $e
 */
function exceptionHandler($e)
{
	// Display this exception
	displayTrace('EXCEPTION', $e->getMessage(), $e->getFile(), $e->getLine(), $e->getTrace());
}


/**
 * Displays and error or excpetion with all its information
 * as well as the trace of its occurence in a list.
 *
 * @param string $label
 * @param string $string
 * @param string $file
 * @param string $line
 * @param array $stacktrace
 */
function displayTrace($label, $string, $file, $line, $stacktrace)
{
	// Show html shizzel
	echo '<style>p,ol,li{font:13px monospace}ol{list-style:decimal-leading-zero}ol li{padding:5px}ol li:nth-child(odd){background:#eee}</style>'."\n";
	echo '<p>'."\n";
	echo '  <b>'.$label.'</b> in '.removePathBaseFromPath($file).'('.$line.')<br><br>'."\n";
	echo '  <i>'.$string.'</i><br><br>'."\n";
	echo '  <ol reversed="reversed">'."\n";

	// Iterate over all trace elements
	foreach($stacktrace as $key => $row)
	{
		// Args buffer
		$args = array();

		// Check whether some function args are given
		if(isset($row['args']))
		{
			// Iterate over all args
			foreach($row['args'] as $arg)
			{
				// Check the types and prepare the string
				if(is_string($arg))
				{
					$args[] = '\''.$arg.'\'';
				}
				if(is_null($arg))
				{
					$args[] = 'null';
				}
				if(is_bool($arg))
				{
					$args[] = $arg ? 'true' : 'false';
				}
				if(is_object($arg))
				{
					$args[] = get_class($arg);
				}
			}
		}

		echo '    <li>'."\n";
		echo '      '.removePathBaseFromPath($row['file']).'('.$row['line'].'):'."\n";
		echo '      <i>'.(isset($row['class'], $row['type']) ? $row['class'].$row['type'] : '').$row['function'].'('.implode(', ', $args).')</i>'."\n";
		echo '    </li>'."\n";
	}
	echo '  </ol>'."\n";
	echo '</p>';
	exit(1);
}

